#ifndef HPP_SIGSLOT_HPP
#define HPP_SIGSLOT_HPP

#include <tuple>
#include <functional>
#include <type_traits>
#include <atomic>
#include <unordered_map>
#include <queue>
#include <optional>
#include <thread>
#include <condition_variable>
#include <shared_mutex>
#include <memory>
#include <string_view>

namespace SigSlot
{
	class EventLoop;

	class Object;

	template<typename ...Args>
	class Event;
	namespace details
	{
		template<typename Subset, typename Superset>
		struct is_subset_of;

		template<typename T, typename ...Subset, typename U, typename ...Superset>
		struct is_subset_of<std::tuple<T, Subset...>, std::tuple<U, Superset...>>
		{
			constexpr static bool value = is_subset_of<std::tuple<T, Subset...>, std::tuple<Superset...>>::value;
		};

		template<typename T, typename ...Subset, typename ...Superset>
		struct is_subset_of<std::tuple<T, Subset...>, std::tuple<T, Superset...>>
		{
			constexpr static bool value = is_subset_of<std::tuple<Subset...>, std::tuple<Superset...>>::value;
		};

		template<typename ...Superset>
		struct is_subset_of<std::tuple<>, std::tuple<Superset...>> : std::true_type {};

		template<typename ...Subset>
		struct is_subset_of<std::tuple<Subset...>, std::tuple<>> : std::false_type {};

		template<>
		struct is_subset_of<std::tuple<>, std::tuple<>> : std::true_type {};


		template<int N, typename T, typename Tuple>
		struct find_next_index;

		template<int N, typename T, typename U, typename ...Args>
		struct find_next_index<N, T, std::tuple<U, Args...>>
		{
			constexpr static int value = find_next_index<N - 1, T, std::tuple<Args...>>::value + 1;
		};
		template<typename T, typename ...Args>
		struct find_next_index<-1, T, std::tuple<T, Args...>>
		{
			constexpr static int value = 0;
		};
		template<typename T, typename U, typename ...Args>
		struct find_next_index<-1, T, std::tuple<U, Args...>>
		{
			constexpr static int value = find_next_index<-1, T, std::tuple<Args...>>::value + 1;
		};

		template<int ...Args>
		struct int_list
		{
			using type = int_list<Args...>;

			template<typename Tuple>
			constexpr static auto MakeTupleByList(const Tuple& target) noexcept
			{
				return std::forward_as_tuple(std::get<Args>(target)...);
			}
		};

		template<int N, typename list>
		struct list_prepend;

		template<int N, int ...Args>
		struct list_prepend<N, int_list<Args...>>
		{
			using result = int_list<N, Args...>;
		};

		template<int N, typename Subset, typename Superset>
		struct find_all_index;

		template<int N, typename T, typename ...Subset, typename ...Superset>
		struct find_all_index<N, std::tuple<T, Subset...>, std::tuple<Superset...>>
		{
			using value = typename list_prepend<find_next_index<N, T, std::tuple<Superset...>>::value,
				typename find_all_index<find_next_index<N, T, std::tuple<Superset...>>::value, std::tuple<Subset...>, std::tuple<Superset...>>::value>::result;
		};

		template<int N, typename ...Superset>
		struct find_all_index<N, std::tuple<>, std::tuple<Superset...>>
		{
			using value = int_list<>;
		};


		template<typename ...Subset, typename ...Superset>
		constexpr auto FunctionCall(const std::function<void(Subset...)>& func, const std::tuple<Superset...>& target) noexcept
		{
			using SubsetTuple = std::tuple<std::decay_t<Subset>...>;
			using SupersetTuple = std::tuple<std::decay_t<Superset>...>;

			if constexpr (is_subset_of<SubsetTuple, SupersetTuple>::value)
			{
				using IndexList = typename find_all_index<-1, SubsetTuple, SupersetTuple>::value;
				std::apply(func, IndexList::MakeTupleByList(target));
			}
		}

		template<typename T>
		struct lambda_traits;

		template<typename T, typename U, typename ...Args>
		struct lambda_traits<T(U::*)(Args...)>
		{
			using parameter_tuple_type = std::tuple<std::decay_t<Args>...>;
		};

		template<typename T, typename U, typename ...Args>
		struct lambda_traits<T(U::*)(Args...) const>
		{
			using parameter_tuple_type = std::tuple<std::decay_t<Args>...>;
		};

		template<typename T>
		struct member_function_traits;

		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...)>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};

		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...)&>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};


		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...) const>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};

		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...) const&>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};


		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...) volatile>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};

		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...) volatile&>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};

		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...) const volatile>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};

		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...) const volatile&>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};

		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...) noexcept>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};

		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...) & noexcept>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};

		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...) const noexcept>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};

		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...) const& noexcept>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};

		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...) volatile noexcept>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};

		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...) volatile& noexcept>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};

		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...) const volatile noexcept>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};

		template<typename R, typename C, typename... Args>
		struct member_function_traits<R(C::*)(Args...) const volatile& noexcept>
		{
			using return_type = R;
			using class_type = C;
			using args_type = std::tuple<Args...>;
		};

		template<typename T, typename U>
		struct is_object : std::false_type {};

		template<typename T>
		struct is_object<T, decltype(std::declval<T>().ThreadId())> : std::true_type {};

		template<typename T>
		constexpr bool is_object_v()
		{
			return is_object<T, std::thread::id>::value;
		}

		template<typename T>
		constexpr std::enable_if_t<std::is_same_v<SigSlot::Object, decltype(std::declval<T>()._SIGSLOTOBJECT_)>, SigSlot::Object&> GetObject(T* object)
		{
			return object->_SIGSLOTOBJECT_;
		}

		constexpr SigSlot::Object& GetObject(SigSlot::Object* object)
		{
			return *object;
		}

		template<typename SubTuple, typename SuperTuple>
		struct is_subset_of_decay_t;

		template<typename ...SubArgs, typename ...SuperArgs>
		struct is_subset_of_decay_t<std::tuple<SubArgs...>, std::tuple<SuperArgs...>>
		{
			constexpr static bool value = is_subset_of<std::tuple<std::decay_t<SubArgs>...>, std::tuple<std::decay_t<SuperArgs>...>>::value;
		};

		template<typename SubTuple, typename SuperTuple>
		using Result = std::enable_if_t<is_subset_of_decay_t<SubTuple, SuperTuple>::value>;


		template<typename ...Args>
		class EventHandlerInterface
		{
		public:
			virtual ~EventHandlerInterface() = default;

			virtual void operator()(const Args &...args) = 0;
		};

		template<typename T, typename Tuple, typename ...Args>
		class EventHandler final : public EventHandlerInterface<Args...> {};

		template<typename ...SlotArgs, typename ...Args>
		class EventHandler<void, std::tuple<SlotArgs...>, Args...> final : public EventHandlerInterface<Args...>
		{
		private:
			std::function<void(SlotArgs...)> m_Handler;
		public:
			EventHandler(const EventHandler& eventHandler) = delete;
			EventHandler& operator=(const EventHandler& eventHandler) = delete;
			EventHandler(EventHandler&& eventHandler) = delete;
			EventHandler& operator=(EventHandler&& eventHandler) = delete;

			template<typename Callable>
			explicit EventHandler(Callable&& func) noexcept
			{
				m_Handler = std::forward<Callable>(func);
			}

			void operator()(const Args &... args) final
			{
				FunctionCall(m_Handler, std::forward_as_tuple(args...));
			}
		};

		template<typename T, typename ...SlotArgs, typename ...Args>
		class EventHandler<T, std::tuple<SlotArgs...>, Args...> final : public EventHandlerInterface<Args...>
		{
			using FunctionPointer = void (T::*)(SlotArgs...);
			using ConstFunctionPointer = void (T::*)(SlotArgs...) const;
		private:
			T* m_Receiver;
			std::function<void(T*, SlotArgs...)> m_Handler;
		public:
			EventHandler(const EventHandler& eventHandler) = delete;
			EventHandler& operator=(const EventHandler& eventHandler) = delete;
			EventHandler(EventHandler&& eventHandler) = delete;
			EventHandler& operator=(EventHandler&& eventHandler) = delete;

			template<typename Callable>
			EventHandler(T* receiver, Callable handler) noexcept
			{
				m_Receiver = receiver;
				m_Handler = handler;
			}

			void operator()(const Args &...args) final
			{
				FunctionCall(m_Handler, std::forward_as_tuple(m_Receiver, args...));
			}
		};

		struct Address
		{
		private:
			void* object;
			char member[16];
		public:
			Address() noexcept : object(nullptr), member() {}

			template<typename T, typename Slot>
			constexpr Address(T* receiver, Slot handler) noexcept : object(receiver), member()
			{
				memcpy(&member, &handler, (sizeof(handler) > 16 ? 16 : sizeof(handler)));
			}

			template<typename T, typename U, typename ...Args>
			constexpr Address(T* sender, Event<Args...> U::* event) noexcept : object(sender), member()
			{
				memcpy(&member, &event, (sizeof(event) > 16 ? 16 : sizeof(event)));
			}

			template<typename ...Args>
			constexpr explicit Address(void(*handler)(Args...)) noexcept : object(nullptr), member()
			{
				memcpy(&member, &handler, (sizeof(handler) > 16 ? 16 : sizeof(handler)));
			}

			bool operator==(const Address& other) const noexcept
			{
				return other.object == object && std::string_view{ member } == std::string_view{ other.member };
			}

			std::size_t operator()(const Address& address) const
			{
				return std::hash<void*>()(address.object) ^
					std::hash<std::string_view>()(std::string_view{ address.member });
			}
		};

		class EventLoopManager
		{
		private:
			std::unordered_map<std::thread::id, EventLoop*> m_EventLoops;
			std::mutex m_Mutex;
			EventLoopManager() = default;
			~EventLoopManager() = default;

			static EventLoopManager& GetInstance() noexcept
			{
				static EventLoopManager instance;
				return instance;
			}

		public:
			EventLoopManager(const EventLoopManager&) = delete;
			EventLoopManager& operator=(const EventLoopManager&) = delete;

			static void AddEventLoop(EventLoop* loop)
			{
				std::unique_lock<std::mutex> lock(GetInstance().m_Mutex);
				GetInstance().m_EventLoops.insert(std::make_pair(std::this_thread::get_id(), loop));
			}

			static void RemoveEventLoop()
			{
				std::unique_lock<std::mutex> lock(GetInstance().m_Mutex);
				if (GetInstance().m_EventLoops.count(std::this_thread::get_id()))
				{
					GetInstance().m_EventLoops.erase(std::this_thread::get_id());
				}
			}

			static EventLoop* GetEventLoop(std::thread::id id)
			{
				std::unique_lock<std::mutex> lock(GetInstance().m_Mutex);
				if (GetInstance().m_EventLoops.count(id))
				{
					return GetInstance().m_EventLoops[id];
				}
				return nullptr;
			}
		};

	}


	//声明
	enum SIGSLOT
	{
		AutoConnection,
		DirectConnection,
		QueuedConnection,
		BlockingQueuedConnection,
	};

	class Object;

	template<typename ...Args>
	class Event;

	class EventLoop;

	static EventLoop* GetEventLoop(std::thread::id id = std::this_thread::get_id());
	static EventLoop* GetEventLoop(const std::thread& thread);

	//member function
	template<typename Sender, typename ...SignalArgs, typename Slot, typename T, typename U>
	inline constexpr details::Result<typename details::member_function_traits<Slot>::args_type, std::tuple<SignalArgs...>>
		connect(T* sender, Event<SignalArgs...> Sender::* event, U* receiver, Slot handler, SIGSLOT type = AutoConnection);

	template<typename Sender, typename ...SignalArgs, typename Slot, typename T, typename U>
	inline constexpr details::Result<typename details::member_function_traits<Slot>::args_type, std::tuple<SignalArgs...>>
		disconnect(T* sender, Event<SignalArgs...> Sender::* event, U* receiver, Slot handler);

	template<typename Sender, typename Receiver, typename Lambda, typename ...SignalArgs, typename T>
	inline constexpr details::Result<typename details::lambda_traits<decltype(&std::decay_t<Lambda>::operator())>::parameter_tuple_type, std::tuple<SignalArgs...>>
		connect(T* sender, Event<SignalArgs...> Sender::* event, Receiver* receiver, Lambda&& lambda, SIGSLOT type = AutoConnection);

	template<typename Sender, typename ...SignalArgs, typename ...SlotArgs, typename T>
	inline constexpr details::Result<std::tuple<std::decay_t<SlotArgs>...>, std::tuple<SignalArgs...>>
		connect(T* sender, Event<SignalArgs...> Sender::* event, void(*handler)(SlotArgs...));

	template<typename Sender, typename ...SignalArgs, typename ...SlotArgs, typename T>
	inline constexpr details::Result<std::tuple<std::decay_t<SlotArgs>...>, std::tuple<SignalArgs...>>
		disconnect(T* sender, Event<SignalArgs...> Sender::* event, void(*handler)(SlotArgs...));

	class EventLoop
	{
	private:
		std::mutex m_Mutex;
		std::condition_variable m_Condition;
		std::deque<std::function<void()>> m_Messages;
		std::atomic<bool> m_Quit{};
	public:
		EventLoop() noexcept
		{
			details::EventLoopManager::AddEventLoop(this);
			m_Quit = false;
		}

		~EventLoop()
		{
			details::EventLoopManager::RemoveEventLoop();
			Quit();
		}

		template<typename Callable>
		void PostEvent(Callable&& func)
		{
			std::unique_lock<std::mutex> lock(m_Mutex);
			m_Messages.push_back(std::forward<Callable>(func));
			lock.unlock();
			m_Condition.notify_all();
		}

		template<typename Callable>
		void SendEvent(Callable&& func)
		{
			std::unique_lock<std::mutex> lock(m_Mutex);
			std::atomic<bool> Finished = false;
			m_Messages.push_back([func = std::forward<Callable>(func), &Finished]()
			{
				func();
				Finished = true;
			});
			m_Condition.notify_all();
			m_Condition.wait(lock, [&Finished]
				{
					return Finished.load();
				});
		}

		void Update()
		{
			std::unique_lock<std::mutex> lock(m_Mutex);
			m_Condition.wait(lock, [this]
				{
					return !m_Messages.empty() || m_Quit;
				});
			std::optional<std::function<void()>> func;
			if (!m_Messages.empty())
			{
				func = std::move(m_Messages.front());
				m_Messages.pop_front();
			}
			lock.unlock();
			if (func.has_value())
			{
				func.value()();
			}
			m_Condition.notify_all();
		}

		void Run()
		{
			m_Quit = false;
			while (!m_Quit)
			{
				Update();
			}
		}

		void Quit()
		{
			m_Quit = true;
			m_Condition.notify_all();
		}

	};

	class Thread
	{
	private:
		std::atomic<std::thread::id> id;
		std::thread thread;
	public:
		Thread(const Thread& other) = delete;
		Thread& operator=(const Thread& other) = delete;

		Thread(Thread&& other) noexcept
		{
			id = other.id.load();
			thread = std::move(other.thread);
		}

		Thread& operator=(Thread&& other) noexcept
		{
			id = other.id.load();
			thread = std::move(other.thread);
			return *this;
		}

		template<typename Callable, typename ...Args>
		explicit Thread(Callable&& func, Args &&... args)
			:thread([&]()
				{
					id = std::this_thread::get_id();
					std::forward<Callable>(func)(std::forward<Args>(args)...);
				})
		{
			while (GetEventLoop(id) == nullptr)
			{
				std::this_thread::yield();
			}
		}

				~Thread()
				{
					thread.detach();
				}

				[[nodiscard]] std::thread::id GetId() const
				{
					return id.load();
				}
	};

	template<typename ...Args>
	class Event
	{
	private:
		struct Handler
		{
			std::thread::id id;
			std::shared_ptr<details::EventHandlerInterface<Args...>> handler;
			SIGSLOT type = AutoConnection;
		};
	private:
		std::unordered_map<details::Address, Handler, details::Address> m_Handlers;
		mutable std::shared_mutex m_Mutex;
	private:
		void AddHandler(const details::Address& address, const Handler& handler)
		{
			std::unique_lock<std::shared_mutex> lock(m_Mutex);
			if (!m_Handlers.count(address))
			{
				m_Handlers.insert(std::make_pair(address, handler));
			}
		}

		void RemoveHandler(const details::Address& address)
		{
			std::unique_lock<std::shared_mutex> lock(m_Mutex);
			if (m_Handlers.count(address))
			{
				m_Handlers.erase(address);
			}
		}

	public:
		~Event()
		{
			m_Handlers.clear();
		}

		void emit(const Args &... args)
		{
			std::shared_lock<std::shared_mutex> lock(m_Mutex);
			for (auto&& [address, connection] : m_Handlers)
			{
				switch (connection.type)
				{
				case SIGSLOT::AutoConnection:
				{
					if (connection.id == std::this_thread::get_id())
					{
						(*connection.handler)(args...);
					}
					else
					{
						EventLoop* loop = details::EventLoopManager::GetEventLoop(connection.id);
						if (loop != nullptr)
						{
							loop->PostEvent([handler = connection.handler, args...]
								{
									(*handler)(args...);
								});
						}
					}
					break;
				}
				case SIGSLOT::DirectConnection:
				{
					(*connection.handler)(args...);
					break;
				}
				case SIGSLOT::QueuedConnection:
				{
					EventLoop* loop = details::EventLoopManager::GetEventLoop(connection.id);
					if (loop != nullptr)
					{
						loop->PostEvent([handler = connection.handler, args...]
							{
								(*handler)(args...);
							});
					}
					break;
				}
				case SIGSLOT::BlockingQueuedConnection:
				{
					EventLoop* loop = details::EventLoopManager::GetEventLoop(connection.id);
					if (loop != nullptr)
					{
						loop->SendEvent([handler = connection.handler, args...]
							{
								(*handler)(args...);
							});
					}
					break;
				}
				}
			}
		}

		template<typename Sender, typename ...SignalArgs, typename Slot, typename T, typename U>
		friend constexpr details::Result<typename details::member_function_traits<Slot>::args_type, std::tuple<SignalArgs...>>
			connect(T* sender, Event<SignalArgs...> Sender::* event, U* receiver, Slot handler, SIGSLOT type);

		template<typename Sender, typename ...SignalArgs, typename Slot, typename T, typename U>
		friend constexpr details::Result<typename details::member_function_traits<Slot>::args_type, std::tuple<SignalArgs...>>
			disconnect(T* sender, Event<SignalArgs...> Sender::* event, U* receiver, Slot handler);

		template<typename Sender, typename Receiver, typename Lambda, typename ...SignalArgs, typename T>
		friend constexpr details::Result<typename details::lambda_traits<decltype(&std::decay_t<Lambda>::operator())>::parameter_tuple_type, std::tuple<SignalArgs...>>
			connect(T* sender, Event<SignalArgs...> Sender::* event, Receiver* receiver, Lambda&& lambda, SIGSLOT type);

		template<typename Sender, typename ...SignalArgs, typename ...SlotArgs, typename T>
		friend constexpr details::Result<std::tuple<std::decay_t<SlotArgs>...>, std::tuple<SignalArgs...>>
			connect(T* sender, Event<SignalArgs...> Sender::* event, void(*handler)(SlotArgs...));

		template<typename Sender, typename ...SignalArgs, typename ...SlotArgs, typename T>
		friend constexpr details::Result<std::tuple<std::decay_t<SlotArgs>...>, std::tuple<SignalArgs...>>
			disconnect(T* sender, Event<SignalArgs...> Sender::* event, void(*handler)(SlotArgs...));

	};

	class Object
	{
	private:
		using Connection = std::unordered_map<details::Address, std::function<void()>, details::Address>;
		std::atomic<std::thread::id> m_Id;
		std::unordered_map<details::Address, Connection, details::Address> m_SendersList;
		std::unordered_map<details::Address, std::function<void()>, details::Address> m_ReceiversList;
		mutable std::shared_mutex m_Mutex;
	private:
		template<typename Callable>
		void AddSender(const details::Address& senderAddress, const details::Address& functionAddress, Callable&& func)
		{
			std::unique_lock<std::shared_mutex> lock(m_Mutex);
			m_SendersList[senderAddress].insert(std::make_pair(functionAddress, std::forward<Callable>(func)));
		}

		template<typename Callable>
		void AddReceiver(const details::Address& receiverAddress, Callable&& func)
		{
			std::unique_lock<std::shared_mutex> lock(m_Mutex);
			m_ReceiversList[receiverAddress] = std::forward<Callable>(func);
		}

		void RemoveSender(const details::Address& senderAddress, const details::Address& functionAddress)
		{
			std::unique_lock<std::shared_mutex> lock(m_Mutex);
			if (m_SendersList.count(senderAddress))
			{
				if (m_SendersList.at(senderAddress).count(functionAddress))
				{
					m_SendersList.at(senderAddress).erase(functionAddress);
				}
			}
		}

		void RemoveReceiver(const details::Address& address)
		{
			std::unique_lock<std::shared_mutex> lock(m_Mutex);
			if (m_ReceiversList.count(address))
			{
				m_ReceiversList.erase(address);
			}
		}

		bool ContainSender(const details::Address& address) const
		{
			std::shared_lock<std::shared_mutex> lock(m_Mutex);
			return m_SendersList.count(address);
		}

		bool ContainReceiver(const details::Address& address) const
		{
			std::shared_lock<std::shared_mutex> lock(m_Mutex);
			return m_ReceiversList.count(address);
		}

	private:

	public:
		Object() : m_Id(std::this_thread::get_id()), m_SendersList{}, m_ReceiversList(), m_Mutex() {}

		virtual ~Object()
		{
			for (auto& pair : m_SendersList)
			{
				for (auto& func : pair.second)
				{
					func.second();
				}
			}
			for (auto& receiver : m_ReceiversList)
			{
				(receiver.second)();
			}
		}

		void MoveToThread(const std::thread& target) noexcept
		{
			m_Id = target.get_id();
		}

		void MoveToThread(const std::thread::id& id) noexcept
		{
			m_Id = id;
		}

		void MoveToThread(const Thread& other) noexcept
		{
			m_Id = other.GetId();
		}

		std::thread::id ThreadId() const noexcept
		{
			return m_Id;
		}

		template<typename Sender, typename ...SignalArgs, typename Slot, typename T, typename U>
		friend constexpr details::Result<typename details::member_function_traits<Slot>::args_type, std::tuple<SignalArgs...>>
			connect(T* sender, Event<SignalArgs...> Sender::* event, U* receiver, Slot handler, SIGSLOT type);

		template<typename Sender, typename ...SignalArgs, typename Slot, typename T, typename U>
		friend constexpr details::Result<typename details::member_function_traits<Slot>::args_type, std::tuple<SignalArgs...>>
			disconnect(T* sender, Event<SignalArgs...> Sender::* event, U* receiver, Slot handler);

		template<typename Sender, typename Receiver, typename Lambda, typename ...SignalArgs, typename T>
		friend constexpr details::Result<typename details::lambda_traits<decltype(&std::decay_t<Lambda>::operator())>::parameter_tuple_type, std::tuple<SignalArgs...>>
			connect(T* sender, Event<SignalArgs...> Sender::* event, Receiver* receiver, Lambda&& lambda, SIGSLOT type);

		template<typename Sender, typename ...SignalArgs, typename ...SlotArgs, typename T>
		friend constexpr details::Result<std::tuple<std::decay_t<SlotArgs>...>, std::tuple<SignalArgs...>>
			connect(T* sender, Event<SignalArgs...> Sender::* event, void(*handler)(SlotArgs...));

		template<typename Sender, typename ...SignalArgs, typename ...SlotArgs, typename T>
		friend constexpr details::Result<std::tuple<std::decay_t<SlotArgs>...>, std::tuple<SignalArgs...>>
			disconnect(T* sender, Event<SignalArgs...> Sender::* event, void(*handler)(SlotArgs...));

	};

	template<typename Sender, typename ...SignalArgs, typename Slot, typename T, typename U>
	inline constexpr details::Result<typename details::member_function_traits<Slot>::args_type, std::tuple<SignalArgs...>>
		connect(T* sender, Event<SignalArgs...> Sender::* event, U* receiver, Slot handler, SIGSLOT type)
	{
		using Receiver = details::member_function_traits<Slot>::class_type;
		using SlotArgs = typename details::member_function_traits<Slot>::args_type;

		details::Address ReceiverAddress(receiver, handler);
		details::Address SenderAddress(sender, event);

		using Handler = typename Event<SignalArgs...>::Handler;
		Handler v_handler;
		v_handler.handler = std::make_shared<details::EventHandler<Receiver, SlotArgs, SignalArgs...>>(static_cast<Receiver*>(receiver), handler);
		v_handler.type = type;
		v_handler.id = std::this_thread::get_id();

		constexpr bool is_object_v = details::is_object_v<Sender>() && details::is_object_v<Receiver>();
		constexpr bool is_not_object_v = !details::is_object_v<Sender>() && !details::is_object_v<Receiver>();
		static_assert(is_object_v || is_not_object_v, "Sender and Receiver must both be Object or neither be");
		if constexpr (is_object_v)
		{
			v_handler.id = static_cast<Receiver*>(receiver)->ThreadId();
			details::GetObject(static_cast<Sender*>(sender)).AddReceiver(ReceiverAddress, [=]()
				{
					details::GetObject(static_cast<Receiver*>(receiver)).RemoveSender(SenderAddress, ReceiverAddress);
				});
			details::GetObject(static_cast<Receiver*>(receiver)).AddSender(SenderAddress, ReceiverAddress, [=]()
				{
					(static_cast<Sender*>(sender)->*event).RemoveHandler(ReceiverAddress);
					details::GetObject(static_cast<Sender*>(sender)).RemoveReceiver(ReceiverAddress);
				});
		}
		(static_cast<Sender*>(sender)->*event).AddHandler(ReceiverAddress, v_handler);

	}

	template<typename Sender, typename ...SignalArgs, typename Slot, typename T, typename U>
	inline constexpr details::Result<typename details::member_function_traits<Slot>::args_type, std::tuple<SignalArgs...>>
		disconnect(T* sender, Event<SignalArgs...> Sender::* event, U* receiver, Slot handler)
	{
		using Receiver = details::member_function_traits<Slot>::class_type;

		details::Address ReceiverAddress(receiver, handler);
		details::Address SenderAddress(sender, event);

		constexpr bool is_object_v = details::is_object_v<Sender>() && details::is_object_v<Receiver>();
		constexpr bool is_not_object_v = !details::is_object_v<Sender>() && !details::is_object_v<Receiver>();
		static_assert(is_object_v || is_not_object_v, "Sender and Receiver must both be Object or neither be");
		if constexpr (is_object_v)
		{
			details::GetObject(static_cast<Sender*>(sender)).RemoveReceiver(ReceiverAddress);
			details::GetObject(static_cast<Receiver*>(receiver)).RemoveSender(SenderAddress, ReceiverAddress);
		}
		(static_cast<Sender*>(sender)->*event).RemoveHandler(ReceiverAddress);
	}

	template<typename Sender, typename Receiver, typename Lambda, typename ...SignalArgs, typename T>
	inline constexpr details::Result<typename details::lambda_traits<decltype(&std::decay_t<Lambda>::operator())>::parameter_tuple_type, std::tuple<SignalArgs...>>
		connect(T* sender, Event<SignalArgs...> Sender::* event, Receiver* receiver, Lambda&& lambda, SIGSLOT type)
	{
		details::Address ReceiverAddress(static_cast<Receiver*>(receiver), &std::decay_t<Lambda>::operator());
		details::Address SenderAddress(static_cast<Sender*>(sender), event);

		using Handler = typename Event<SignalArgs...>::Handler;
		Handler v_handler;
		v_handler.handler = std::make_shared<details::EventHandler<void, typename details::lambda_traits<decltype(&std::decay_t<Lambda>::operator())>::parameter_tuple_type, SignalArgs...>>(std::forward<Lambda>(lambda));
		v_handler.type = type;
		v_handler.id = std::this_thread::get_id();

		constexpr bool is_object_v = details::is_object_v<Sender>() && details::is_object_v<Receiver>();
		constexpr bool is_not_object_v = !details::is_object_v<Sender>() && !details::is_object_v<Receiver>();
		static_assert(is_object_v || is_not_object_v, "Sender and Receiver must both be Object or neither be");
		if constexpr (is_object_v)
		{
			v_handler.id = static_cast<Receiver*>(receiver)->ThreadId();
			details::GetObject(static_cast<Sender*>(sender)).AddReceiver(ReceiverAddress, [=]()
				{
					details::GetObject(static_cast<Receiver*>(receiver)).RemoveSender(SenderAddress, ReceiverAddress);
				});
			details::GetObject(static_cast<Receiver*>(receiver)).AddSender(SenderAddress, ReceiverAddress, [=]()
				{
					(static_cast<Sender*>(sender)->*event).RemoveHandler(ReceiverAddress);
					details::GetObject(static_cast<Sender*>(sender)).RemoveReceiver(ReceiverAddress);
				});
		}
		(static_cast<Sender*>(sender)->*event).AddHandler(ReceiverAddress, v_handler);
	}

	template<typename Sender, typename ...SignalArgs, typename ...SlotArgs, typename T>
	inline constexpr details::Result<std::tuple<std::decay_t<SlotArgs>...>, std::tuple<SignalArgs...>>
		connect(T* sender, Event<SignalArgs...> Sender::* event, void(*handler)(SlotArgs...))
	{
		using Handler = typename Event<SignalArgs...>::Handler;
		Handler v_handler;
		v_handler.handler = std::make_shared<details::EventHandler<void, std::tuple<SlotArgs...>, SignalArgs...>>(handler);
		v_handler.type = SIGSLOT::DirectConnection;
		v_handler.id = std::this_thread::get_id();
		(static_cast<Sender*>(sender)->*event).AddHandler(details::Address(handler), v_handler);
	}

	template<typename Sender, typename ...SignalArgs, typename ...SlotArgs, typename T>
	inline constexpr details::Result<std::tuple<std::decay_t<SlotArgs>...>, std::tuple<SignalArgs...>>
		disconnect(T* sender, Event<SignalArgs...> Sender::* event, void(*handler)(SlotArgs...))
	{
		(static_cast<Sender*>(sender)->*event).RemoveHandler(details::Address(handler));
	}

	inline EventLoop* GetEventLoop(std::thread::id id)
	{
		return details::EventLoopManager::GetEventLoop(id);
	}

	inline EventLoop* GetEventLoop()
	{
		return GetEventLoop(std::this_thread::get_id());
	}

	inline EventLoop* GetEventLoop(const Thread& thread)
	{
		return GetEventLoop(thread.GetId());
	}

	inline EventLoop* GetEventLoop(const std::thread& thread)
	{
		return GetEventLoop(thread.get_id());
	}
}
#define SIGSLOT_OBJECT \
    public:\
        SigSlot::Object _SIGSLOTOBJECT_;\
        void MoveToThread(const std::thread &SIGSLOT_TARGET) noexcept\
        {\
            _SIGSLOTOBJECT_.MoveToThread(SIGSLOT_TARGET.get_id());\
        }\
\
        void MoveToThread(const std::thread::id &SIGSLOT_ID) noexcept\
        {\
            _SIGSLOTOBJECT_.MoveToThread(SIGSLOT_ID);\
        }\
\
        void MoveToThread(const SigSlot::Thread &SIGSLOT_OTHER) noexcept\
        {\
            _SIGSLOTOBJECT_.MoveToThread(SIGSLOT_OTHER.GetId());\
        }\
\
        std::thread::id ThreadId() noexcept\
        {\
            return _SIGSLOTOBJECT_.ThreadId();\
        }\
    private:
#endif //HPP_SIGSLOT_HPP
